package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.comment.dtos.CommentLikeDto;
import com.heima.comment.dtos.CommentListDto;
import com.heima.comment.dtos.CommentSaveDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.service.CommentService;
import com.heima.comment.vos.ApCommentVo;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.HotArticleConstants;
import com.heima.common.mess.UpdateArticleMess;
import com.heima.feign.client.ApUserFeignClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.thread.ApThreadLocal;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Resource
    private ApUserFeignClient apUserFeignClient;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private MongoTemplate mongoTemplate;

    @Resource
    private GreenTextScan greenTextScan;

    @Resource
    private KafkaTemplate<String,String> kafkaTemplate;

    /**
     * 发表评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1.参数校验
        if(dto.getArticleId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"文章id为空");
        }
        if(dto.getContent()==null || dto.getContent().length()>140){
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"评论内容为空或者内容长度超过140");
        }
        //1.5 对文本内容进行垃圾检测
        boolean textFlag = this.textScan(dto.getContent());
        if(!textFlag){
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"文本内容中包含敏感词，审核不通过");
        }


        //2.获取用户id
        ApUser apUser = ApThreadLocal.getApUser();
        if(apUser==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"用户信息为空，需求登录操作");
        }
        if(apUser.getId()==0){//游客身份
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"游客身份不可以评论，需要登录之后才可以");
        }

        //3.先从redis中去查询用户信息   redis的类型是字符串
        //定义redis的key    value表示用户信息的实体对象
        String userKey="LOGIN_USER_"+apUser.getId();
        String userStr = stringRedisTemplate.opsForValue().get(userKey);

        //4.如果存在，则直接使用redis中的数据信息
        if(userStr!=null){
            apUser = JSON.parseObject(userStr, ApUser.class);
        }
        //5.如果不存在，则远程调用用户信息，然后保存一份到redis中
        else{
            //远程调用fegin接口
            ResponseResult responseResult = apUserFeignClient.findById(apUser.getId());
            if(responseResult.getCode()==200){
                apUser = (ApUser) responseResult.getData();
                //保存数据到redis
                stringRedisTemplate.opsForValue().set(userKey,JSON.toJSONString(apUser));
            }
        }

        //6.保存数据到mongo中
        ApComment apcomment=new ApComment();
        apcomment.setUserId(apUser.getId());
        apcomment.setImage(apUser.getImage());
        apcomment.setLikes(0);
        apcomment.setReply(0);
        apcomment.setNickName(apUser.getName());
        apcomment.setContent(dto.getContent());
        apcomment.setUpdatedTime(new Date());
        apcomment.setCreatedTime(new Date());
        apcomment.setTargetId(dto.getArticleId().toString());
        mongoTemplate.save(apcomment);

        //封装发送消息的内容
        UpdateArticleMess mess=new UpdateArticleMess();
        mess.setArticleId(dto.getArticleId());
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        mess.setAdd(1);
        //发送消息内容给kafka
        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC, JSON.toJSONString(mess));

        return ResponseResult.okResult("发布评论成功");
    }



    private boolean textScan(String content) {

        boolean flag=true;

        try {
            Map scanTextMap = greenTextScan.greeTextScan(content);
            //违规，审核不通过
            if(scanTextMap.get("suggestion").equals("block")){
                flag=false;
            }
            //表示需要人工审核
            if(scanTextMap.get("suggestion").equals("review")){
                flag=false;
            }

        } catch (Exception e) {
            e.printStackTrace();
            flag=false;
        }
        return  flag;
    }


    /**
     * 点赞评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult likeComment(CommentLikeDto dto) {
        //1.参数校验
        if(dto.getCommentId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2.获取用户id
        ApUser apUser = ApThreadLocal.getApUser();
        if(apUser==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"用户信息为空，需要登录操作");
        }
        if(apUser.getId()==0){//游客身份
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN,"游客身份不可以点赞，需要登录之后才可以");
        }


        /**
         *  3.查询评论集合是否存在
         *  findById(Object id, Class<T> entityClass);
         *  参数1表示主键id,类型是objectId
         *  参数2表示class对象
         */
        ApComment apComment = mongoTemplate.findById(new ObjectId(dto.getCommentId()), ApComment.class);
        if(apComment==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"当前评论信息不存在");
        }
        //4.查询redis中是否点赞过
        String likeKey="COMMENT_LIEK_"+apUser.getId();
        /**
         * redis中key= "COMMENT_LIKE_"+用户id
         * value是一个set类型的集合，存储的是每个点赞过的评论id
         */
        Boolean memberFlag = stringRedisTemplate.opsForSet().isMember(likeKey, dto.getCommentId());

        //5.如果点赞过，并且此刻正在执行的是点赞动作，则直接返回
        if(memberFlag && dto.getOperation()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST,"当前用户已经点赞过该评论");
        }

        //6.如果点赞过，并且此刻正在执行的是取消点赞动作，则删除redis和mongo(评论集合点赞数-1，删除点赞集合)
        if(memberFlag && dto.getOperation()==1){
            //删除redis
            stringRedisTemplate.opsForSet().remove(likeKey,dto.getCommentId());
            //删除mongo点赞集合
            mongoTemplate.remove(Query.query(
                    Criteria.where("userId").is(apUser.getId()).and("targetId").is(dto.getCommentId())
                    ),
                    ApCommentLike.class);
            //修改mongo的评论集合的点赞数量-1
            Update update=new Update();
            update.inc("likes",-1);//防止数字小于0
            mongoTemplate.updateFirst(
                    Query.query(
                            Criteria.where("id").is(dto.getCommentId())
                    ),
                    update,
                    ApComment.class
            );
        }

        //7.如果没有点赞过，并且此刻正在执行的是点赞动作，新增redis和mongo(评论集合点赞数+1，新增点赞集合)
        if(!memberFlag && dto.getOperation()==0){
            //新增redis
            stringRedisTemplate.opsForSet().add(likeKey,dto.getCommentId());
            //新增点赞集合mongo
            ApCommentLike apCommentLike=new ApCommentLike();
            apCommentLike.setTargetId(dto.getCommentId());
            apCommentLike.setUserId(apUser.getId());
            apCommentLike.setCreatedTime(new Date());
            mongoTemplate.insert(apCommentLike);
            //修改评论集合mongo,点赞数量+1
            Update update=new Update();
            update.inc("likes",1);
            mongoTemplate.updateFirst(
                    Query.query(
                            Criteria.where("id").is(dto.getCommentId())
                    ),
                    update,
                    ApComment.class
            );
        }

        //8.返回数据信息
        //由于前端代码中需要一个likes是当前这个评论信息的点赞，返回前台
        Map map=new HashMap();
        //根据评论id再次去查询mongo中的点赞数
        apComment=mongoTemplate.findById(new ObjectId(dto.getCommentId()), ApComment.class);
        map.put("likes",apComment.getLikes());

        return ResponseResult.okResult(map);
    }

    /**
     * 加载评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult listComment(CommentListDto dto) {
        //1.参数校验
        if(dto.getArticleId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getSize()==null || dto.getSize()==0){
            dto.setSize(10);
        }

        //2.根据文章id去查询mongo的评论表，并进行分页和排序展示
        List<ApComment> commentList = mongoTemplate.find(Query.query(
                Criteria.where("targetId").is(dto.getArticleId().toString())//别忘了转成字符串才可以
                        .and("createdTime").lte(dto.getMinDate())//小于2063年
                ).with(Sort.by(Sort.Direction.DESC, "createdTime"))//排序
                        .limit(dto.getSize())//分页设置
                , ApComment.class);

        //3如果没有数据，则直接返回
        if(commentList==null || commentList.size()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"没有查询到评论信息");
        }

        //4如果有数据，判断是否是游客身份
        ApUser apUser = ApThreadLocal.getApUser();
        if(apUser.getId()==0){
            //5如果是游客身份，则直接返回list
            return ResponseResult.okResult(commentList);
        }
        //6如果不是游客身份，则返回是否点赞过的标识
        //否则就是用户登录，加载数据的时候，要判断当前用户点赞了哪些评论，并给予标识
        String likeKey="COMMENT_LIEK_"+apUser.getId();
        Set<String> membersSet = stringRedisTemplate.opsForSet().members(likeKey);
        if(membersSet==null || membersSet.size()==0){
            //表示没有查询到点赞记录,直接返回list
            return ResponseResult.okResult(commentList);
        }

        //否则就一定有点赞过的记录，对点赞过的进行高亮展示
        List<ApCommentVo> apCommentVoList = commentList.stream().map(comment -> {
            ApCommentVo apCommentVo=new ApCommentVo();
            BeanUtils.copyProperties(comment,apCommentVo);
            if(membersSet.contains(comment.getId())){
                apCommentVo.setOperation((short) 0);//表示被点赞过，相当于进行高亮
            }
            return apCommentVo;
        }).collect(Collectors.toList());

        //7返回数据
        return ResponseResult.okResult(apCommentVoList);
    }

}
